{ "cells": [ { "cell_type": "markdown", "id": "1a2b3c4d-5e6f-7890-1234-567890abcdef", "metadata": {}, "source": [ "# Tutorial 08 - OEM Files and Covariance\n", "\n", "In version 0.9.0, ANISE introduces the ability to read CCSDS OEM (Orbit Ephemeris Message) files and interpolate them, including covariance data. This tutorial demonstrates:\n", "\n", "1. **Reading an OEM File:** Loading an OEM file into an `Ephemeris` object.\n", "2. **Interpolation:** Querying state and covariance at arbitrary times.\n", "3. **Covariance Frames:** Accessing covariance in different frames (RIC, Inertial, etc.).\n", "4. **Event Integration:** Combining OEM data with event finding to query covariance at specific event times." ] }, { "cell_type": "code", "execution_count": 1, "id": "2b3c4d5e-6f78-9012-3456-7890abcdef12", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "=== PLANETARY DATA #0: `../../data/pck08.pca` ===\n", "┌───────┬─────────┬──────────────────────────┬─────────────────┬─────────────────┬─────────────────┬───────────────────────┬─────────────────────┬────────────────────────────────────────────────────────┐\n", "│ Name │ ID │ Gravity param (km^3/s^2) │ Major axis (km) │ Minor axis (km) │ Polar axis (km) │ Pole right asc. │ Pole declination │ Prime meridian │\n", "├───────┼─────────┼───────────────────��──────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤\n", "│ Unset │ 1 │ 22031.78000000002 │ 2439.7 │ 2439.7 │ 2439.7 │ 281.01 + -0.033 t │ 61.45 + -0.005 t │ 329.548 + 6.1385025 t │\n", "├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤\n", "│ Unset │ 2 │ 324858.59200000006 │ 6051.8 │ 6051.8 │ 6051.8 │ 272.76 + 0 t │ 67.16 + 0 t │ 160.2 + -1.4813688 t │\n", "├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼───���────────────────────────────────────────────────────┤\n", "│ Unset │ 3 │ 403503.2355022598 │ Unset │ Unset │ Unset │ Unset │ Unset │ Unset │\n", "├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤\n", "│ Unset │ 4 │ 42828.37521400002 │ Unset │ Unset │ Unset │ Unset │ Unset │ Unset │\n", "├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤\n", "│ Unset │ 5 │ 126712764.8000002 │ Unset │ Unset │ Unset │ Unset │ Unset │ Unset │\n", "├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤\n", "│ Unset │ 6 │ 37940585.2 │ Unset │ Unset │ Unset │ Unset │ Unset │ Unset │\n", "├───────┼─────────┼──────────────────���───────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤\n", "│ Unset │ 7 │ 5794548.600000008 │ Unset │ Unset │ Unset │ Unset │ Unset │ Unset │\n", "├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼──────────��──────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤\n", "│ Unset │ 8 │ 6836527.100580024 │ Unset │ Unset │ Unset │ Unset │ Unset │ Unset │\n", "├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤\n", "│ Unset │ 10 │ 132712440041.93938 │ 696000 │ 696000 │ 696000 │ 286.13 + 0 t │ 63.87 + 0 t │ 84.1 + 14.1844 t │\n", "├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤\n", "│ Unset │ 301 │ 4902.800066163796 │ 1737.4 │ 1737.4 │ 1737.4 │ 269.9949 + 0.0031 t │ 66.5392 + 0.013 t │ 38.3213 + 13.17635815 t │\n", "├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤\n", "│ Unset │ 399 │ 398600.435436096 │ 6378.14 │ 6378.14 │ 6356.75 │ 0 + -0.641 t │ 90 + -0.557 t │ 190.147 + 360.9856235 t │\n", "├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤\n", "│ Unset │ 401 │ 0.0007087546066894452 │ 13.4 │ 11.2 │ 9.2 │ 317.68 + -0.108 t │ 52.9 + -0.061 t │ 35.06 + 1128.844585 t + 0.000000006644300993056522 t^2 │\n", "├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤\n", "│ Unset │ 402 │ 0.00009615569648120313 │ 7.5 │ 6.1 │ 5.2 │ 316.65 + -0.108 t │ 53.52 + -0.061 t │ 79.41 + 285.161897 t │\n", "├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────���───────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤\n", "│ Unset │ 499 │ 42828.37362069909 │ 3396.19 │ 3396.19 │ 3376.2 │ 317.68143 + -0.1061 t │ 52.8865 + -0.0609 t │ 176.63 + 350.89198226 t │\n", "├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼��───────────────────────────────────────────────────────┤\n", "│ Unset │ 501 │ 5959.916033410404 │ 1829.4 │ 1819.3 │ 1815.7 │ 268.05 + -0.009 t │ 64.5 + 0.003 t │ 200.39 + 203.4889538 t │\n", "├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤\n", "│ Unset │ 502 │ 3202.738774922892 │ 1564.13 │ 1561.23 │ 1560.93 │ 268.08 + -0.009 t │ 64.51 + 0.003 t │ 36.022 + 101.3747235 t │\n", "├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤\n", "│ Unset │ 503 │ 9887.834453334144 │ 2632.4 │ 2632.29 │ 2632.35 │ 268.2 + -0.009 t │ 64.57 + 0.003 t ��� 44.064 + 50.3176081 t │\n", "├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤\n", "│ Unset │ 504 │ 7179.28936139727 │ 2409.4 │ 2409.2 │ 2409.3 │ 268.72 + -0.009 t │ 64.83 + 0.003 t │ 259.51 + 21.5710715 t │\n", "├───────┼─────────┼───────────────��──────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤\n", "│ Unset │ 505 │ 0.1378480571202615 │ 125 │ 73 │ 64 │ 268.05 + -0.009 t │ 64.49 + 0.003 t │ 231.67 + 722.631456 t │\n", "├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤\n", "│ Unset │ 599 │ 126686534.9218008 │ 71492 │ 71492 │ 66854 │ 268.05 + -0.009 t │ 64.49 + 0.003 t │ 284.95 + 870.536642 t │\n", "├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────���────────────────────────────────────────────────────────┤\n", "│ Unset │ 601 │ 2.503522884661795 │ 209.1 │ 196.2 │ 191.4 │ 40.66 + -0.036 t │ 83.52 + -0.004 t │ 337.46 + 381.994555 t │\n", "├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼──────────────────────────────────────────────────────��─┤\n", "│ Unset │ 602 │ 7.211292085479989 │ 256.3 │ 247.3 │ 244.6 │ 40.66 + -0.036 t │ 83.52 + -0.004 t │ 2.82 + 262.7318996 t │\n", "├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤\n", "│ Unset │ 603 │ 41.21117207701302 │ 535.6 │ 528.2 │ 525.8 │ 40.66 + -0.036 t │ 83.52 + -0.004 t │ 10.45 + 190.6979085 t │\n", "├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤\n", "│ Unset │ 604 │ 73.11635322923193 │ 560 │ 560 │ 560 │ 40.66 + -0.036 t │ 83.52 + -0.004 t │ 357 + 131.5349316 t │\n", "├───────┼─────────┼──────────────���───────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤\n", "│ Unset │ 605 │ 153.9422045545342 │ 764 │ 764 │ 764 │ 40.38 + -0.036 t │ 83.55 + -0.004 t │ 235.16 + 79.6900478 t │\n", "├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼──────��──────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤\n", "│ Unset │ 606 │ 8978.138845307376 │ 2575 │ 2575 │ 2575 │ 36.41 + -0.036 t │ 83.94 + -0.004 t │ 189.64 + 22.5769768 t │\n", "├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤\n", "│ Unset │ 607 │ 0.3718791714191668 │ 164 │ 130 │ 107 │ Unset │ Unset │ Unset │\n", "├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼─────────────────────────────────────────────────────���──┤\n", "│ Unset │ 608 │ 120.5134781724041 │ 718 │ 718 │ 718 │ 318.16 + -3.949 t │ 75.03 + -1.143 t │ 350.2 + 4.5379572 t │\n", "├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤\n", "│ Unset │ 609 │ 0.5531110414633374 │ 115 │ 110 │ 105 │ 355 + 0 t │ 68.7 + 0 t │ 304.7 + 930.833872 t │\n", "├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤\n", "│ Unset │ 610 │ 0.1266231296945636 │ 97 │ 95 │ 77 │ 40.58 + -0.036 t │ 83.52 + -0.004 t │ 58.83 + 518.2359876 t │\n", "├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤\n", "│ Unset │ 611 │ 0.03513977490568457 │ 69 │ 55 │ 55 │ 40.58 + -0.036 t │ 83.52 + -0.004 t │ 293.87 + 518.4907239 t │\n", "├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────�" ] } ], "source": [ "from pathlib import Path\n", "from anise import Almanac\n", "from anise.astro import Ephemeris, LocalFrame, DataType, Orbit, Frame\n", "from anise.constants import Frames\n", "from anise.time import Epoch, Unit\n", "from anise.analysis import Event, StateSpec, FrameSpec\n", "\n", "# Load a base Almanac (for frame definitions)\n", "almanac = Almanac(\"../../data/pck08.pca\")\n", "almanac.describe()" ] }, { "cell_type": "markdown", "id": "3c4d5e6f-7890-1234-5678-90abcdef1234", "metadata": {}, "source": [ "## 1. Reading an OEM File\n", "\n", "We can load an OEM file directly into an `Ephemeris` object. This object holds the interpolated data." ] }, { "cell_type": "code", "execution_count": 2, "id": "4d5e6f78-9012-3456-7890-abcdef123456", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Loading OEM from ../../data/tests/ccsds/oem/LRO_Nyx.oem\n", "Ephemeris loaded:\n", "2010-LRO ephem from 2024-01-01T00:00:00 UTC to 2024-01-01T00:03:00 UTC (4 states, spans 3 min)\n", "Domain: 2024-01-01T00:00:00 UTC to 2024-01-01T00:03:00 UTC\n" ] } ], "source": [ "oem_path = \"../../data/tests/ccsds/oem/LRO_Nyx.oem\"\n", "print(f\"Loading OEM from {oem_path}\")\n", "\n", "ephem = Ephemeris.from_ccsds_oem_file(oem_path)\n", "print(\"Ephemeris loaded:\")\n", "print(ephem)\n", "\n", "(start, end) = ephem.domain()\n", "print(f\"Domain: {start} to {end}\")" ] }, { "cell_type": "markdown", "id": "5e6f7890-1234-5678-90ab-cdef12345678", "metadata": {}, "source": [ "## 2. Interpolation and Covariance\n", "\n", "We can query the covariance at any time within the domain. ANISE supports transforming the covariance into various local frames:\n", "- **RIC (Radial, In-track, Cross-track):** Also known as RTN.\n", "- **Inertial:** The frame in which the data is defined (usually J2000).\n", "- **VNC (Velocity, Normal, Co-normal):** Useful for maneuver planning.\n", "- **RCN:** Radial, Cross-track, Normal." ] }, { "cell_type": "code", "execution_count": 3, "id": "6f789012-3456-7890-abcd-ef1234567890", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Querying covariance at 2024-01-01T00:01:30 UTC\n", "\n", "Covariance (RIC):\n", "Covariance in RIC\n", " ┌ ┐\n", " │ 0.962697 0.417577 -0.432062 0.004468 0.002043 -0.001881 │\n", " │ 0.417577 0.672621 0.372849 0.002017 0.003435 0.001994 │\n", " │ -0.432062 0.372849 0.832859 -0.001914 0.001990 0.004048 │\n", " │ 0.004468 0.002017 -0.001914 0.000059 0.000024 -0.000022 │\n", " │ 0.002043 0.003435 0.001990 0.000024 0.000036 0.000020 │\n", " │ -0.001881 0.001994 0.004048 -0.000022 0.000020 0.000044 │\n", " └ ┘\n", "\n", "\n", "\n", "Covariance (Inertial):\n", "Covariance in Inertial\n", " ┌ ┐\n", " │ 0.221927 0.425854 0.264891 0.001022 0.001972 0.001206 │\n", " │ 0.425854 1.115708 0.013385 0.001966 0.005345 -0.000217 │\n", " │ 0.264891 0.013385 1.138789 0.001213 -0.000234 0.005647 │\n", " │ 0.001022 0.001966 0.001213 0.000011 0.000022 0.000013 │\n", " │ 0.001972 0.005345 -0.000234 0.000022 0.000062 0.000004 │\n", " │ 0.001206 -0.000217 0.005647 0.000013 0.000004 0.000067 │\n", " └ ┘\n", "\n", "\n" ] } ], "source": [ "query_time = start + (end - start) * 0.5\n", "print(f\"Querying covariance at {query_time}\")\n", "\n", "# Covariance in RIC frame\n", "covar_ric = ephem.covar_at(query_time, LocalFrame.RIC, almanac)\n", "print(\"\\nCovariance (RIC):\")\n", "print(covar_ric)\n", "\n", "# Covariance in Inertial frame\n", "covar_inertial = ephem.covar_at(query_time, LocalFrame.Inertial, almanac)\n", "print(\"\\nCovariance (Inertial):\")\n", "print(covar_inertial)" ] }, { "cell_type": "markdown", "id": "78901234-5678-90ab-cdef-1234567890ab", "metadata": {}, "source": [ "## 3. Combining with Event Finding\n", "\n", "A powerful workflow is to find events using the `Almanac` and then inspect the covariance at those specific times.\n", "\n", "First, we load the OEM into an `Almanac`. We must provide a NAIF ID for the object in the OEM file (e.g., LRO is -85)." ] }, { "cell_type": "code", "execution_count": 6, "id": "89012345-6789-0abc-def1-234567890abc", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "ephemeris contains covariance, which is NOT copied to the SPICE BSP file\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Almanac created from OEM:\n", "=== SPK #0: `2025-12-29T21:07:33.292829705 UTC` ===\n", "┌─────────────────────────────────────────┬────────────────┬────────────┬───────────────────────────────────┬───────────────────────────────────┬──────────┬──────────────────────┐\n", "│ Name │ Target │ Center │ Start epoch │ End epoch │ Duration │ Interpolation kind │\n", "├─────────────────────────────────────────┼────────────────┼───────────���┼───────────────────────────────────┼───────────────────────────────────┼──────────┼──────────────────────┤\n", "│ 2010-LRO (converted by Nyx Space ANISE) │ body -85 J2000 │ Moon J2000 │ 2024-01-01T00:01:09.183898601 TDB │ 2024-01-01T00:04:09.183898727 TDB │ 3 min │ Hermite Unequal Step │\n", "└─────────────────────────────────────────┴────────────────┴────────────┴───────────────────────────────────┴───────────────────────────────────┴──────────┴──────────────────────┘\n" ] } ], "source": [ "lro_id = -85\n", "# Load OEM into a new Almanac, assigning it the LRO ID\n", "almanac_oem = Almanac.from_ccsds_oem_file(oem_path, lro_id)\n", "# Load PCK for frame definitions (needed for event finding involving other bodies or frames)\n", "almanac_oem = almanac_oem.load(\"../../data/pck08.pca\")\n", "\n", "print(\"Almanac created from OEM:\")\n", "almanac_oem.describe(spk=True)" ] }, { "cell_type": "markdown", "id": "90123456-7890-abcd-ef12-34567890abcd", "metadata": {}, "source": [ "Now we define an event, for example, finding apoapsis events... of which there are none because there is only 3 min of data in this ephem" ] }, { "cell_type": "code", "execution_count": 7, "id": "01234567-890a-bcde-f123-4567890abcde", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Searching for apoapsis events...\n", "Found 0 apoapsis events.\n" ] } ], "source": [ "lro_frame = Frame(lro_id, 1) # Assuming J2000 orientation\n", "moon_frame = Frames.MOON_J2000\n", "\n", "lro_state_spec = StateSpec(\n", " target_frame=FrameSpec.Loaded(lro_frame),\n", " observer_frame=FrameSpec.Loaded(moon_frame),\n", " ab_corr=None,\n", ")\n", "\n", "apolune = Event.apoapsis()\n", "\n", "print(f\"Searching for apoapsis events...\")\n", "apo_events = almanac_oem.report_events(lro_state_spec, apolune, start, end)\n", "print(f\"Found {len(apo_events)} apoapsis events.\")" ] }, { "cell_type": "markdown", "id": "12345678-90ab-cdef-1234-567890abcdef", "metadata": {}, "source": [ "Finally, we iterate through the found events and query the covariance from the original `Ephemeris` object at each event time." ] }, { "cell_type": "code", "execution_count": 8, "id": "23456789-0abc-def1-2345-67890abcdef1", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Querying covariance at event times:\n" ] } ], "source": [ "print(\"Querying covariance at event times:\")\n", "for i, event in enumerate(apo_events):\n", " event_time = event.orbit.epoch\n", " \n", " # Query covariance in RIC frame\n", " cov = ephem.covar_at(event_time, LocalFrame.RIC, almanac_oem)\n", " \n", " print(f\"\\nEvent {i+1} at {event_time}:\")\n", " print(cov)" ] }, { "cell_type": "code", "execution_count": null, "id": "1e037b68-6298-4ba6-b226-eea5d258cbef", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.14" } }, "nbformat": 4, "nbformat_minor": 5 }